// Package service
// @Author: zhangdi
// @File: ListenKeyboard
// @Version: 1.0.0
// @Date: 2023/5/30 15:30
package service

import (
	"fmt"
	"github.com/moutend/go-hook/pkg/keyboard"
	"github.com/moutend/go-hook/pkg/types"
	"ideatools/application/pkgs/mylog"
	"strings"
)

const KeyboardKeyPre = "VK_"
const KeyboardBaseKeyPre = "VK_L" //组合键开头
const KeyboardEventPre = "WM_"
const KeyboardEventDown = "KEYDOWN"
const KeyboardEventSysDown = "SYSKEYDOWN"
const KeyboardEventUp = "KEYUP"

const KBPreWinLAlt = "LMENU"
const KBPreWinLCtrl = "LCONTROL"
const KBPreWinLShift = "LSHIFT"

const KBPreWinAlt = "MENU"
const KBPreWinCtrl = "CONTROL"
const KBPreWinShift = "SHIFT"

// CombinedKeyHandler 组合键通知事件
type CombinedKeyHandler func(CombinedKey string)

type ListenKeyboardService struct {
	KeyDownList []string
	handler     CombinedKeyHandler
}

func StartListenKeyboardService(handler_ CombinedKeyHandler) *ListenKeyboardService {
	s := &ListenKeyboardService{
		KeyDownList: make([]string, 0),
		handler:     handler_,
	}
	go s.Listen()

	return s

}

func (s *ListenKeyboardService) Listen() {
	// 设置键盘事件通道的缓冲大小，根据您的需要选择相应的值
	keyboardChan := make(chan types.KeyboardEvent, 100)

	// 安装键盘钩子并将键盘事件发送到 keyboardChan 中处理
	if err := keyboard.Install(nil, keyboardChan); err != nil {
		mylog.Error(err.Error())
		return
	}

	// 在程序结束时卸载键盘钩子
	defer keyboard.Uninstall()

	// 创建一个信号通道用于捕获操作系统发出的终止信号（如Ctrl+C）
	//signalChan := make(chan os.Signal, 1)
	//signal.Notify(signalChan, os.Interrupt)
	for {
		select {
		// 从键盘事件通道中读取键盘事件并处理，若没有键盘事件，则跳过该条case分支
		case k := <-keyboardChan:

			VEvent := fmt.Sprintf("%s", k.Message)
			do := strings.ReplaceAll(VEvent, KeyboardEventPre, "")
			//过滤的到key
			code := s.FilterCode(fmt.Sprintf("%s", k.VKCode))

			if IsKeyDown(do) { //按键按下
				s.AddOneKey(code)

			}

			if do == KeyboardEventUp { //按键抬起
				s.removeOneKey(code)
			}

			continue
		}
	}

}

func (s *ListenKeyboardService) FilterCode(code string) string {
	code = strings.ReplaceAll(code, KeyboardKeyPre, "")
	KeyName := strings.TrimSpace(code)

	if KeyName == KBPreWinLAlt || KeyName == KBPreWinLShift || KeyName == KBPreWinLCtrl {
		KeyName = KeyName[1:]
	}

	return KeyName
}

func (s *ListenKeyboardService) AddOneKey(KeyName string) {

	for _, k := range s.KeyDownList {
		//已存在该按键 则不会再添加
		if k == KeyName {
			return
		}
	}

	s.KeyDownList = append(s.KeyDownList, KeyName)

	s.notify() //调用通知
}

// 移除一个按键 前缀Prefix 后缀Suffix
func (s *ListenKeyboardService) removeOneKey(KeyName string) {
	newList := make([]string, 0)
	for _, k := range s.KeyDownList {
		if KeyName != k {
			newList = append(newList, k)
		}
	}

	s.KeyDownList = newList
}

func IsKeyDown(do string) bool {
	//如果按键是 alt 会走到KeyboardEventSysDown
	if do == KeyboardEventDown || do == KeyboardEventSysDown {
		return true
	}
	return false
}

// 如果按键中组合键数量大于1 则调用通知回调
func (s *ListenKeyboardService) notify() {

	if len(s.KeyDownList) > 1 {
		keys := strings.Join(s.KeyDownList, "+")
		if s.HasPreKey() {
			s.handler(keys)
		}

	}
}

// HasPreKey 判断是否包含前缀按键
func (s *ListenKeyboardService) HasPreKey() bool {
	for _, k := range s.KeyDownList {
		if k == KBPreWinCtrl {
			return true
		}
		if k == KBPreWinShift {
			return true
		}
		if k == KBPreWinAlt {
			return true
		}

	}
	return false
}
